from datetime import datetime

from decimal import Decimal

from django.db import transaction
from django_redis import get_redis_connection
from rest_framework import serializers

from goods.models import SKU
from orders.models import OrderInfo, OrderGoods


class OrderSerializer(serializers.ModelSerializer):
    """订单信息序列化器"""
    count = serializers.IntegerField(label='商品数量')

    class Meta:
        model = SKU
        fields = ('id', 'name', 'price', 'default_image_url', 'count')


class OrderCreateSerializer(serializers.ModelSerializer):
    """订单创建序列化器"""

    class Meta:
        model = OrderInfo
        fields = ('order_id', 'address', 'pay_method')
        read_only_fields = ('order_id',)

        extra_kwargs = {
            'address': {
                'write_only': True,
                'required': True
            },
            'pay_method': {
                'write_only': True,
                'required': True
            }
        }

    def create(self, validated_data):
        address = validated_data['address']
        pay_method = validated_data['pay_method']

        user = self.context['request'].user
        order_id = datetime.now().strftime('%Y%m%d%H%M%S') + '%010d' % user.id

        total_count = 0
        total_amount = 0

        freight = Decimal(10)

        # if pay_method == OrderInfo.PAY_METHODS_ENUM['CASH']:
        #     status = OrderInfo.ORDER_STATUS_ENUM['UNPAID']
        # if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY']:
        #     status = OrderInfo.ORDER_STATUS_ENUM['UNSEND']

        status = OrderInfo.ORDER_STATUS_ENUM['UNSEND'] if pay_method == OrderInfo.PAY_METHODS_ENUM['CASH'] else \
        OrderInfo.ORDER_STATUS_ENUM['UNPAID']

        with transaction.atomic():
            # with语句块下面的代码，凡是涉及到数据库操作的代码，在进行数据库操作时，都会放在同一个事务中

            # 设置事务保存点
            sid = transaction.savepoint()
            # 保存订单信息
            try:
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    pay_method=pay_method,
                    total_count=total_count,
                    total_amount=total_amount,
                    status=status,
                    freight=freight
                )

                # 有多少商品就向订单商品表中增加记录
                conn = get_redis_connection('cart')
                selected_key = 'selected_%s' % user.id
                # 选中的商品id
                sku_ids = conn.smembers(selected_key)
                # (sku_id ........)

                # 商品数量
                key = 'cart_%s' % user.id
                skus_count = conn.hgetall(key)
                # {b'sku_id': b'count'}

                for sku_id in sku_ids:
                    for i in range(3):
                        sku = SKU.objects.get(id=int(sku_id))

                        count = skus_count[sku_id]
                        count = int(count)
                        # 判断商品库存
                        if count > sku.stock:
                            transaction.savepoint_rollback(sid)
                            raise serializers.ValidationError('库存不足')

                        # 库存减少,销量增加
                        origin_stock = sku.stock

                        new_stock = origin_stock - count
                        new_sales = sku.sales + count

                        # 模拟订单并发问题
                        # print('user: %s times: %s stock: %s' % (user.id, i, origin_stock))
                        # import time
                        # time.sleep(10)

                        res = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock, sales=new_sales)
                        if res == 0:
                            if i == 2:
                                transaction.savepoint_rollback(sid)
                                raise serializers.ValidationError('下单失败')
                            continue
                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            count=count,
                            price=sku.price,
                        )
                        # 计算商品总价格及总数量
                        total_count += count
                        total_amount = sku.price * total_count

                        # 走到这里说明没问题了,跳出循环
                        break
                # 更新商品信息表中商品总价格和总数量
                order.total_count = total_count
                order.total_amount = total_amount + freight
                order.save()
            except serializers.ValidationError:
                raise
            except Exception as e:
                transaction.savepoint_rollback(sid)
                raise serializers.ValidationError('下单失败1')

        # 清除redis中购物车信息
        conn.hdel(key, *sku_ids)
        conn.srem(selected_key, *sku_ids)

        # 返回应答
        return order
